package com.micro.common.config;

import com.alibaba.fastjson.JSON;
import com.micro.common.constant.Constant;
import com.micro.common.constant.R;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author pan.shun
 * @since 2022/3/15 17:17
 */
@SuppressWarnings("unchecked")
@Slf4j
public class AdminInterceptor implements HandlerInterceptor {

    private RedisTemplate redisTemplate;

    AdminInterceptor(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 在请求处理之前进行调用（Controller方法调用之前）
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {

        if ("OPTIONS".equals(request.getMethod())) {
            log.info("CORS跨域复杂请求发送一个方法为OPTIONS的预检请求");
            response.setStatus(HttpServletResponse.SC_OK);
            return true;
        } else {
            String token = request.getHeader(Constant.TOKEN_CONFIG.TOKEN_KEY);
            if (StringUtils.isEmpty(token)) {
                token = request.getParameter(Constant.TOKEN_CONFIG.TOKEN_KEY);
            }
            log.info("当前用户Token {}", token);

            if (StringUtils.isEmpty(token)) {
                sendResponse(response, "请携带令牌进行访问");
                return false;
            }
            try {
                Claims body = Jwts.parser().setSigningKey
                        (Constant.TOKEN_CONFIG.SIGNINGKEY).parseClaimsJws(token).getBody();
                String tokenId = body.getId();

                String cacheKey = Constant.TOKEN_CONFIG.PREFIX + tokenId;
                if (!redisTemplate.hasKey(cacheKey)) {
                    sendResponse(response, "登录已失效,请重新登录");
                    return false;
                }
            } catch (ExpiredJwtException | SignatureException e) {
                sendResponse(response, "登录已失效,请重新登录");
                return false;
            } catch (Exception e) {
                sendResponse(response, "登录验证失败,请重新登录");
                return false;
            }
            return true;
        }
    }

    @SuppressWarnings("unchecked")
    private void sendResponse(HttpServletResponse response, String msg) {
        try {
            response.setContentType("text/html;charset=utf-8");
            response.setCharacterEncoding("UTF-8");
            PrintWriter pw = new PrintWriter(response.getOutputStream());
            R r = new R(401, msg, null);
            pw.write(JSON.toJSONString(r));
            pw.close();
        } catch (IOException e) {
            log.error("响应异常 :{}", e);
        }
    }


    /**
     * 请求处理之后进行调用，但是在视图被渲染之前（Controller方法调用之后）
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
    }

    /**
     * 在整个请求结束之后被调用，也就是在DispatcherServlet 渲染了对应的视图之后执行（主要是用于进行资源清理工作）
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    }
}